

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const util = require('./util.js');

const resolve = dir => path.resolve(__dirname, '../../', dir || '');
const root = resolve(); // 根目录
const output = resolve('appStatic'); // 输出目录
const srcRoot = resolve('src/app'); // 源码目录
const jeSrcRoot = resolve('src-je'); // 源码目录
const includeDir = [srcRoot, resolve('node_modules')];
const mode = process.env.NODE_ENV; // 环境
const dev = mode === 'development'; // 开发
const publicPath = './'; // 资源引用路径

let cfg = {};
if (dev) {
  // eslint-disable-next-line global-require
  cfg = require('./webpack.dev.js');
} else {
  // eslint-disable-next-line global-require
  cfg = require('./webpack.prod.js');
}
const entrys = util.buildEntry();
const entryConfigs = util.buildEntryConfigs();
const webpackConfig = merge(
  {
    // 当我们在require一个模块的时候，如果在require中包含变量
    context: root,
    // 定义入口文件, 指示webpack使用哪个模块作为构建其内部依赖图开始，进入起点后依赖项被处理
    entry: entrys,
    devtool: 'none',
    // 当我们想在项目中require一些其他的类库或者API，而又不想让这些类库的源码被构建到运行时文件中，这在实际开发中很有必要。
    externals: {
      // 不打包的第三方库
      vue: 'Vue',
    },
    stats: {},
    // 入口可以有多个，出口只能有一个！
    // output参数是个对象，用于定义构建后的文件的输出。其中包含path和filename
    output: {
      path: output,
      publicPath,
      filename(file) { return util.buildFileName(file, 'js'); },
      libraryTarget: 'umd',
      umdNamedDefine: true,
    },
    // webpack在构建包的时候会按目录的进行文件的查找，resolve属性中的extensions数组中用于配置程序可以自行补全哪些文件后缀
    resolve: {
      extensions: ['.js', '.vue', '.json', '.css', '.less'],
      alias: {
        '@': srcRoot,
        '@je': jeSrcRoot,
        '@root': root,
        mui: resolve('public/js/mui.min.js'),
        node_modules: resolve('node_modules'),
      },
    },
    // 这里通过正则表达式去匹配不同后缀的文件名，然后给它们定义不同的加载器
    module: {
      rules: [
        {
          test: /\.(css|postcss|less)(\?.*)?$/,
          include: includeDir,
          use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            'postcss-loader',
            { loader: 'less-loader', options: { javascriptEnabled: true } },
          ],
        },
        {
          test: /\.vue$/,
          loader: 'vue-loader',
          include: includeDir,
          options: {
            extractCSS: true,
          },
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          include: includeDir,
        },
        {
          enforce: 'pre',
          test: /\.(vue|(j|t)sx?)$/,
          exclude: [
            /node_modules/,
          ],
          use: [
            {
              loader: 'eslint-loader',
              options: {
                extensions: [
                  '.js',
                  '.jsx',
                  '.vue',
                ],
                cache: true,
                cacheIdentifier: '4d9a30a4',
                emitWarning: true,
                emitError: false,
                formatter() { /* omitted long function */ },
              },
            },
          ],
        },
        {
          test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
          loader: 'url-loader',
          include: includeDir,
          options: {
            limit: 100000,
            publicPath: util.buildPublicPath,
            name(url) {
              return util.buildAssetsUrl(url, 'images');
            },
          },
        },
        {
          test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
          loader: 'url-loader',
          include: includeDir,
          options: {
            limit: 10000,
            publicPath: util.buildPublicPath,
            name(url) {
              return util.buildAssetsUrl(url, 'media');
            },
          },
        },
        {
          test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
          loader: 'url-loader',
          include: includeDir,
          options: {
            limit: 10000,
            publicPath: util.buildPublicPath,
            name(url) {
              return util.buildAssetsUrl(url, 'fonts');
            },
          },
        },
      ],
    },
    // 插件 -- 解决loader无法实现的其他事，功能从打包优化到重新定义环境中的变量，使用一个插件，只需要require（）插件，而后将其添加到plugins数组中
    plugins: [
      // 处理hash的插件
      new util.HashUtil(),
      // 在一个配置文件中，因为不同目的多次使用同一个插件时，用new操作符创建一个实例
      new VueLoaderPlugin(),
      new MiniCssExtractPlugin({
        // 抽取css
        filename(file) { return util.buildFileName(file, 'css'); },
        chunkFilename: '[name]/index.[chunkhash:7].css',
      }),
      new CleanWebpackPlugin(['appStatic/'], {
        root: path.resolve(__dirname, '../../'),
        verbose: true,
        dry: false,
      }),
      new webpack.DefinePlugin({
        'process.env': {
          // 项目变量
          PRODUCT_CONFIG: JSON.stringify(process.env.PRODUCT_CONFIG),
        },
      }),
      new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(zh-cn)$/),
    ],
  },
  cfg
);

// 多页面配置
webpackConfig.plugins = webpackConfig.plugins.concat(util.buildPages(webpackConfig.entry));
module.exports = webpackConfig;
